/*
    description:循环队列 任意固定字节大小的数据出入队
    remark:     编译必须是文件名大写加上_DEBUG才能编译成功
*/
#include "round_queue.h"
#include <pthread.h>
#include <sys/time.h>
#include <unistd.h>
#include "../global.h"

#define QUEUE_SIZE    (2560)


bool IsQueueEmpty(ROUND_QUEUE *que)
{
    return que->bIsEmpty;
}


bool IsQueueFill(ROUND_QUEUE *que)
{
    return que->bIsFill;
}


int PushRoundQue(ROUND_QUEUE *que, uint8_t *pBuf, uint16_t len)
{
    if (NULL == que || NULL == que->pQueBuf)
    {
        return -1;
    }

    if (que->bIsFill)
    {
        return 0;
    }

    // pthread_mutex_lock(&mutex); // 加锁
    // printf("PushRoundQue %d %d %d %d %d %d %d %d\n", pBuf[0], pBuf[1], pBuf[2], pBuf[3], pBuf[4], pBuf[5], pBuf[6], pBuf[7]);

    if (que->pWrite >= que->pRead)
    {
        if (que->pWrite + len -1 <= que->pTail) // 在tail时仍可写数据
        {
            memcpy(que->pWrite, pBuf, len);
            que->pWrite += len;
        }
        else
        {
            // 跨界了
            uint16_t temp = que->pTail - que->pWrite + 1;
            // 判断跨界后，队列还能否能容纳该长度数据，不能则队列满了，等队列pop
            if (que->pHead + len - temp > que->pRead)
            {
                que->bIsFill = true;

                return 0;
            }
            memcpy(que->pWrite, pBuf, temp);
            memcpy(que->pHead, pBuf + temp, len - temp);

            que->pWrite = que->pHead + len - temp;
        }
    }
    else if (que->pWrite < que->pRead)
    {
        if (que->pWrite + len <= que->pRead) // 在read处不能将当前的数据写入
        {
            memcpy(que->pWrite, pBuf, len);

            que->pWrite += len;              // 可以等于pRead
        }
        else
        {
            // 队列容不下这个长度
            que->bIsFill = true;

            return 0;
        }
    }
    else
    {
        // 应该不会有这种情况
    }

    // 限幅
    if (que->pWrite > que->pTail)
    {
        if (que->pRead >= (que->pHead + (que->pWrite - que->pTail) - 1))
        {
            que->pWrite = que->pHead + (que->pWrite - que->pTail) - 1;
        }
        else
        {
            // 这种情况应该也不会出现
        }

    }

    que->bIsEmpty = false;

    if (que->pWrite == que->pRead)
    {
        que->bIsFill = true;
    }

    // pthread_mutex_unlock(&mutex); // 解锁
    return len;
}


int PopRoundQue(ROUND_QUEUE *que, uint8_t *pBuf, uint16_t len)
{
    if (NULL == que || NULL == que->pQueBuf)
    {
        return -1;
    }

    if (que->bIsEmpty)
    {
        return 0;
    }
    // pthread_mutex_lock(&mutex); // 加锁

    if (que->pRead >= que->pWrite)
    {
        if (que->pRead + len -1 <= que->pTail)
        {
            // 没越界
            memcpy(pBuf, que->pRead, len);

            que->pRead += len;
        }
        else
        {
            // 越界copy
            uint16_t temp = que->pTail - que->pRead + 1;
            memcpy(pBuf, que->pRead, temp);
            memcpy(pBuf + temp, que->pHead, len - temp);

            que->pRead = que->pHead + (len - temp);
        }
    }
    else if (que->pRead < que->pWrite)
    {
        if (que->pRead + len <= que->pWrite)
        {
            memcpy(pBuf, que->pRead, len);

            que->pRead += len;
        }
        else
        {
            // 队列中可读长度小于要读的长度，说明当前队列空的
            que->bIsEmpty = true;
        }
    }
    else
    {
        // 应该也不会有这种情况
    }

    que->bIsFill = false;

    // 限幅
    if (que->pRead > que->pTail)
    {
        if (que->pWrite >= (que->pHead + (que->pRead - que->pTail) - 1))
        {
            que->pRead = que->pHead + (que->pRead - que->pTail) - 1;
        }


    }

    if (que->pWrite == que->pRead)
    {
        que->bIsEmpty = true;
    }

    return len;

}


ROUND_QUEUE* CreateRoundQue(uint16_t u16QueSize)
{
    if (0 >= u16QueSize)
    {
        return NULL;
    }

    ROUND_QUEUE* que = (ROUND_QUEUE *)malloc(sizeof(*que));

    if (NULL == que)
    {
        return que;
    }

    que->pQueBuf = (uint8_t *)malloc(sizeof(uint8_t) * u16QueSize);
    if (NULL == que->pQueBuf)
    {
        free(que);
        que = NULL;
        return que;
    }

    que->bIsFill  = false;
    que->bIsEmpty = true;
    que->pHead    = que->pQueBuf;
    que->pTail    = que->pHead + u16QueSize - 1;
    que->pWrite   = que->pHead;
    que->pRead    = que->pWrite;

    que->IsEmpty  = IsQueueEmpty;
    que->IsFill   = IsQueueFill;
    que->Push     = PushRoundQue;
    que->Pop      = PopRoundQue;

    return que;
}


/* 使用循环队列 */
#ifdef ROUND_QUEUE_DEBUG
static void *push_func1(void *arg) {
    if (NULL == arg)
    {
        return NULL;
    }
    TRACE(DEBUG, "push_func1");

    if (NULL == arg)
    {
        TRACE(ERROR, "NULL == arg");
        return NULL;
    }
    ROUND_QUEUE* que = (ROUND_QUEUE *)arg;
    uint8_t data[QUEUE_SIZE / 2];
    for (uint32_t i = 0; i < TABLESIZE(data); i++)
    {
        data[i] = i;
    }

    while (1)
    {
        usleep(1 * 1000);
        // pthread_mutex_lock(&mutex); // 加锁
        int ret = que->Push(que, data, sizeof(data));
        // pthread_mutex_unlock(&mutex); // 解锁

        if (ret < 0)
        {
            TRACE(ERROR, "round queue init fail!");
        }
        else if (ret == 0)
        {
            TRACE(DEBUG, "que is fill");
            // printf("755 %p %p %p %p\n", que->pHead, que->pTail, que->pRead, que->pWrite);
            uint8_t *temp = que->pQueBuf;
            // for (uint8_t i =0; i < 16; i++)
            // {
            //     printf("%d ", temp[i]);
            // }printf("<-\n");
            usleep(600 * 1000);
        }
        else
        {
            TRACE(DEBUG, "push data succ");
        }
    }


    return NULL;
}

static void *pop_func2(void *arg) {

    if (NULL == arg)
    {
        return NULL;
    }
    TRACE(DEBUG, "pop_func2");

    ROUND_QUEUE* que = (ROUND_QUEUE *)arg;
    uint8_t data[QUEUE_SIZE / 2];
    memset(data, 0, sizeof(data));

    while (1)
    {
        usleep(2 * 1000);
        // pthread_mutex_lock(&mutex); // 加锁
        int ret = que->Pop(que, data, sizeof(data));
        // pthread_mutex_unlock(&mutex); // 解锁
        if (ret < 0)
        {
            TRACE(ERROR, "round queue init fail!\n");
        }
        else if (ret == 0)
        {
            TRACE(WARNING, "que is empty\n");
            usleep(200 * 1000);
        }
        else
        {
            TRACE(DEBUG, "pop data success");
            // uint16_t sum = 0;
            // for (uint8_t i = 0; i < sizeof(data); i++)
            // {
            //     sum += data[i];
            //     // printf("%d ", data[i]);
            // }
            // // printf("\n");

            // if (28 != sum)
            // {
            //     printf("!!!! error sum = %d\n", sum);

            //     for (uint8_t i = 0; i < sizeof(data); i++)
            //     {
            //         printf("%d ", data[i]);
            //     }
            //     printf("\n");
            // }
        }
    }

    return NULL;
}




int main_(int argc, char * argv[])
{
    ROUND_QUEUE* round_que = CreateRoundQue(QUEUE_SIZE);
    if (NULL == round_que)
    {
        TRACE(ERROR, "round_que == NULL");
        return 0;
    }

    TRACE(DEBUG, "round_que = %p", round_que);
}
int main(int argc, char * argv[])
{
    pthread_t tid1, tid2;
    pthread_mutex_t mutex;                       // 定义互斥锁
    ROUND_QUEUE* round_que = NULL;

    round_que = CreateRoundQue(QUEUE_SIZE);
    if (NULL == round_que)
    {
        TRACE(ERROR, "round_que == NULL");
        return 0;
    }

    pthread_mutex_init(&mutex, NULL);            // 初始化互斥锁


    TRACE(DEBUG, "run ......\n");
    pthread_create(&tid1, NULL, push_func1, round_que);
    pthread_create(&tid2, NULL, pop_func2, round_que);

    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);


    return 0;
}

#endif

